using Geek.Server.App.Logic.WebServer;
using Geek.Server.Core.Actors;
using Geek.Server.Core.Utils;

namespace Server.Logic.WebServer
{
    /// <summary>
    /// 中心服 帐号鉴权功能
    /// </summary>
    public partial class WebServerCompAgent
    {
        private void OnActiveAuth()
        {
            // 将sdk uid和账号id进行绑定
            foreach (var (accountId, accountInfo) in Comp.State.AccountMap)
            {
                if (accountInfo.Id == 0)
                    accountInfo.Id = accountId;// 修复旧数据
                foreach (var (sdkType, sdkUid) in accountInfo.SDKUidMap)
                {
                    var encodeUid = EncodeSDKUid(sdkUid, sdkType);
                    Comp.SDKUidToAccountInfoMap[encodeUid] = accountInfo;
                }
            }
        }

        [Service]
        public virtual Task<WebAuthResp> RequestCreateLoginToken(string sdkUid, LoginSDKType sdkType)
        {
            var accountInfo = GetAccountInfo(sdkUid, sdkType);
            var accountId = accountInfo.Id;
            var token = MurmurHash3.Hash($"{accountId}_{DateTime.Now.Ticks}").ToString();
            Comp.AccountTokenMap[accountId] = token;

            ServerInfo recommendServer = null;
            if (accountInfo.RoleMap != null && accountInfo.RoleMap.Count > 0)
            {
                DateTime recentLoginTime = DateTime.MinValue;
                foreach (var (serverId, roleInfo) in accountInfo.RoleMap)
                {
                    if (!Comp.State.ServerMap.TryGetValue(serverId, out var serverInfo))
                        continue;

                    if (recommendServer != null && roleInfo.LastLoginTime < recentLoginTime)
                        continue;

                    recommendServer = serverInfo;
                    recentLoginTime = roleInfo.LastLoginTime;
                }
            }

            if (recommendServer == null)
            {
                ServerInfo recentOpenServer = null;
                DateTime recentOpenTime = DateTime.MinValue;

                foreach (var (_, serverInfo) in State.ServerMap)
                {
                    if (serverInfo.Flags.HasFlag(ServerFlags.Recommend))
                    {
                        recommendServer = serverInfo;
                        break;
                    }

                    if (recentOpenServer != null && serverInfo.OpenTime < recentOpenTime)
                        continue;

                    recentOpenServer = serverInfo;
                    recentOpenTime = serverInfo.OpenTime;
                }

                recommendServer ??= recentOpenServer;
            }

            return Task.FromResult(new WebAuthResp
            {
                AccountId = accountId,
                LoginToken = token,
                RecommendServer = recommendServer
            });
        }

        [Service]
        public virtual Task<HttpResponse> RequestAuthLoginToken(long accountId, string loginToken)
        {
            if (!Comp.AccountTokenMap.TryGetValue(accountId, out var token) || token != loginToken)
                return Task.FromResult(HttpResponse.Create((int)MessageErrorCode.LoginTokenIsInvalid));

            // 票据只能使用一次
            Comp.AccountTokenMap.Remove(accountId);
            return Task.FromResult(HttpResponse.Create());
        }

        /// <summary>
        /// 通过sdk uid获取账号id 若不存在则创建新的账号id并进行绑定
        /// </summary>
        private AccountInfo GetAccountInfo(string sdkUid, LoginSDKType sdkType)
        {
            var encodeUid = EncodeSDKUid(sdkUid, sdkType);
            if (Comp.SDKUidToAccountInfoMap.TryGetValue(encodeUid, out var accountInfo))
                return accountInfo;

            var accountId = IdGenerator.GetUniqueId(IDModule.Account);

            accountInfo = new AccountInfo();
            accountInfo.Id = accountId;
            accountInfo.SDKUidMap[sdkType] = sdkUid;

            Comp.State.AccountMap[accountId] = accountInfo;
            Comp.SDKUidToAccountInfoMap[encodeUid] = accountInfo;

            return accountInfo;
        }

        /// <summary>
        /// 拼接sdk uid
        /// </summary>
        private static string EncodeSDKUid(string sdkUid, LoginSDKType sdkType)
        {
            return $"{(int)sdkType}_{sdkUid}";
        }
    }
}